home *** CD-ROM | disk | FTP | other *** search
/ Aminet 24 / Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso / Aminet / comm / mail / Mutt089src.lha / Mutt-0.89i-AMIGA / src / parse.c < prev    next >
C/C++ Source or Header  |  1998-01-28  |  31KB  |  1,292 lines

  1. /*
  2.  * Copyright (C) 1996-8 Michael R. Elkins <me@cs.hmc.edu>
  3.  * 
  4.  *     This program is free software; you can redistribute it and/or modify
  5.  *     it under the terms of the GNU General Public License as published by
  6.  *     the Free Software Foundation; either version 2 of the License, or
  7.  *     (at your option) any later version.
  8.  * 
  9.  *     This program is distributed in the hope that it will be useful,
  10.  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  *     GNU General Public License for more details.
  13.  * 
  14.  *     You should have received a copy of the GNU General Public License
  15.  *     along with this program; if not, write to the Free Software
  16.  *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  */ 
  18.  
  19. #include "mutt.h"
  20. #include "mutt_regex.h"
  21. #include "mailbox.h"
  22. #include "mime.h"
  23. #include "parse.h"
  24. #include "rfc2047.h"
  25. #ifdef _PGPPATH
  26. #include "pgp.h"
  27. #endif /* _PGPPATH */
  28.  
  29. #include <string.h>
  30. #include <ctype.h>
  31. #include <sys/stat.h>
  32. #include <stdlib.h>
  33.  
  34. /* Reads an arbitrarily long header field, and looks ahead for continuation
  35.  * lines.  ``line'' is dynamically increased if more space is required to fit
  36.  * the whole line.
  37.  */
  38. char *mutt_read_rfc822_line (FILE *f, char *line, size_t *linelen)
  39. {
  40.   size_t offset = 0, l;
  41.   char buf[LONG_STRING];
  42.   char ch, *pbuf, *q;
  43.   int is_cont = 0; /* continuation line? */
  44.   int is_full;
  45.  
  46.   if (line)
  47.     *line = 0;
  48.  
  49.   FOREVER
  50.   {
  51.     if (fgets (buf, sizeof (buf), f) == NULL)
  52.       return (line);
  53.  
  54.     /* check to see if we got a full line */
  55.     l = strlen (buf);
  56.     is_full = (!l || buf[l - 1] == '\n');
  57.  
  58.     pbuf = buf;
  59.     if (is_cont)
  60.     {
  61.       /* unfold the continuation line, as described by MIME */
  62.       for (; ISSPACE (*pbuf); pbuf++, l--) /* empty */
  63.     ;
  64.       if (*pbuf)
  65.       {
  66.     *--pbuf = ' '; /* convert to a single space */
  67.     l++;
  68.       }
  69.     }
  70.     is_cont = 0;
  71.  
  72.     /* if we got a full line, remove trailing space */
  73.     if (l && pbuf[l - 1] == '\n')
  74.     {
  75.       for (q = pbuf + l - 1 ; q >= pbuf && ISSPACE (*q) ; q--, l--)
  76.         *q = 0;
  77.     }
  78.  
  79.     if (offset + l > *linelen)
  80.     {
  81.       /* not enough space to hold the (rest of the) line, grow the buffer */
  82.       if (line)
  83.       {
  84.     *linelen = offset + l;
  85.     safe_realloc ((void **) &line, *linelen + 1);
  86.       }
  87.       else
  88.       {
  89.     *linelen = l;
  90.     line = safe_malloc (*linelen + 1);
  91.       }
  92.     }
  93.     else if (!l && !line)
  94.     {
  95.       /* Avoid a segfault if the first line we read is blank. */
  96.       return (NULL);
  97.     }
  98.  
  99.     if (l)
  100.     {
  101.       memcpy (line + offset, pbuf, l + 1);
  102.       offset += l;
  103.     }
  104.  
  105.     /* check to see if we got a full line */
  106.     if (!is_full)
  107.       continue; /* no, read the next part */
  108.  
  109.     /* a blank line indicates the end of the message header */
  110.     if (! *line)
  111.       return (line);
  112.  
  113.     /* check to see if the next line is a continuation line */
  114.     ch = fgetc (f);
  115.     ungetc (ch, f);
  116.     if (ch != ' ' && ch != '\t')
  117.       return (line); /* next line is a separate header field or EOH */
  118.     is_cont = 1;
  119.   }
  120.   /* not reached */
  121. }
  122.  
  123. static LIST *mutt_parse_references (char *s)
  124. {
  125.   LIST *t, *lst = NULL;
  126.  
  127.   while ((s = strtok (s, " \t")) != NULL)
  128.   {
  129.     /*
  130.      * some mail clients add other garbage besides message-ids, so do a quick
  131.      * check to make sure this looks like a valid message-id
  132.      */
  133.     if (*s == '<')
  134.     {
  135.       t = (LIST *)safe_malloc (sizeof (LIST));
  136.       t->data = safe_strdup (s);
  137.       t->next = lst;
  138.       lst = t;
  139.     }
  140.     s = NULL;
  141.   }
  142.  
  143.   return (lst);
  144. }
  145.  
  146. int mutt_check_encoding (const char *c)
  147. {
  148.   if (strncasecmp ("7bit", c, sizeof ("7bit")-1) == 0)
  149.     return (ENC7BIT);
  150.   else if (strncasecmp ("8bit", c, sizeof ("8bit")-1) == 0)
  151.     return (ENC8BIT);
  152.   else if (strncasecmp ("binary", c, sizeof ("binary")-1) == 0)
  153.     return (ENCBINARY);
  154.   else if (strncasecmp ("quoted-printable", c, sizeof ("quoted-printable")-1) == 0)
  155.     return (ENCQUOTEDPRINTABLE);
  156.   else if (strncasecmp ("base64", c, sizeof("base64")-1) == 0)
  157.     return (ENCBASE64);
  158.   else
  159.     return (ENCOTHER);
  160. }
  161.  
  162. static PARAMETER *parse_parameters (const char *s)
  163. {
  164.   PARAMETER *head = 0, *cur = 0, *new;
  165.   char buffer[LONG_STRING];
  166.   const char *p;
  167.   size_t i;
  168.  
  169.   while (*s)
  170.   {
  171.     if ((p = strpbrk (s, "=;")) == NULL)
  172.     {
  173.       dprint(1, (debugfile, "parse_parameters: malformed parameter: %s\n", s));
  174.       return (head); /* just bail out now */
  175.     }
  176.  
  177.     /* if we hit a ; now the parameter has no value, just skip it */
  178.     if (*p != ';')
  179.     {
  180.       i = p - s;
  181.  
  182.       new = mutt_new_parameter ();
  183.  
  184.       new->attribute = safe_malloc (i + 1);
  185.       memcpy (new->attribute, s, i);
  186.       new->attribute[i] = 0;
  187.  
  188.       /* remove whitespace from the end of the attribute name */
  189.       while (ISSPACE (new->attribute[--i]))
  190.     new->attribute[i] = 0;
  191.  
  192.       s = p + 1; /* skip over the = */
  193.       SKIPWS (s);
  194.  
  195.       if (*s == '"')
  196.       {
  197.     s++;
  198.     for (i=0; *s && *s != '"' && i < sizeof (buffer) - 1; i++, s++)
  199.     {
  200.       if (*s == '\\')
  201.       {
  202.         /* Quote the next character */
  203.         buffer[i] = s[1];
  204.         if (!*++s)
  205.           break;
  206.       }
  207.       else
  208.         buffer[i] = *s;
  209.     }
  210.     buffer[i] = 0;
  211.     if (*s)
  212.       s++; /* skip over the " */
  213.       }
  214.       else
  215.       {
  216.     for (i=0; *s && *s != ' ' && *s != ';' && i < sizeof (buffer) - 1; i++, s++)
  217.       buffer[i] = *s;
  218.     buffer[i] = 0;
  219.       }
  220.  
  221.       new->value = safe_strdup (buffer);
  222.  
  223.       /* Add this parameter to the list */
  224.       if (head)
  225.       {
  226.     cur->next = new;
  227.     cur = cur->next;
  228.       }
  229.       else
  230.     head = cur = new;
  231.     }
  232.     else
  233.     {
  234.       dprint (1, (debugfile, "parse_parameters(): parameter with no value: %s\n", s));
  235.       s = p;
  236.     }
  237.  
  238.     /* Find the next parameter */
  239.     if (*s != ';' && (s = strchr (s, ';')) == NULL)
  240.     break; /* no more parameters */
  241.  
  242.     do
  243.     {
  244.       s++;
  245.  
  246.       /* Move past any leading whitespace */
  247.       SKIPWS (s);
  248.     }
  249.     while (*s == ';'); /* skip empty parameters */
  250.   }    
  251.  
  252.   return (head);
  253. }
  254.  
  255. int mutt_check_mime_type (const char *s)
  256. {
  257.   if (strcasecmp ("text", s) == 0)
  258.     return TYPETEXT;
  259.   else if (strcasecmp ("multipart", s) == 0)
  260.     return TYPEMULTIPART;
  261.   else if (strcasecmp ("application", s) == 0)
  262.     return TYPEAPPLICATION;
  263.   else if (strcasecmp ("message", s) == 0)
  264.     return TYPEMESSAGE;
  265.   else if (strcasecmp ("image", s) == 0)
  266.     return TYPEIMAGE;
  267.   else if (strcasecmp ("audio", s) == 0)
  268.     return TYPEAUDIO;
  269.   else if (strcasecmp ("video", s) == 0)
  270.     return TYPEVIDEO;
  271.   else
  272.     return TYPEOTHER;
  273. }
  274.  
  275. static void parse_content_type (char *s, BODY *ct)
  276. {
  277.   char *pc;
  278.   char buffer[SHORT_STRING];
  279.   short i = 0;
  280.  
  281.   safe_free((void **)&ct->subtype);
  282.   mutt_free_parameter(&ct->parameter);
  283.  
  284.   /* First extract any existing parameters */
  285.   if ((pc = strchr(s, ';')) != NULL)
  286.   {
  287.     *pc++ = 0;
  288.     while (*pc && ISSPACE (*pc))
  289.       pc++;
  290.     ct->parameter = parse_parameters(pc);
  291.  
  292.     /* Some pre-RFC1521 gateways still use the "name=filename" convention */
  293.     if ((pc = mutt_get_parameter("name", ct->parameter)) != 0)
  294.       ct->filename = safe_strdup(pc);
  295.   }
  296.   
  297.   /* Now get the subtype */
  298.   if ((pc = strchr(s, '/')))
  299.   {
  300.     *pc++ = 0;
  301.     while (*pc && !ISSPACE (*pc) && *pc != ';')
  302.     {
  303.       buffer[i++] = *pc;
  304.       pc++;
  305.     }
  306.     buffer[i] = 0;
  307.     ct->subtype = safe_strdup (buffer);
  308.   }
  309.  
  310.   /* Finally, get the major type */
  311.   ct->type = mutt_check_mime_type (s);
  312.  
  313.   if (ct->subtype == NULL)
  314.   {
  315.     /* Some older non-MIME mailers (i.e., mailtool, elm) have a content-type
  316.      * field, so we can attempt to convert the type to BODY here.
  317.      */
  318.     if (ct->type == TYPETEXT)
  319.       ct->subtype = safe_strdup ("plain");
  320.     else if (ct->type == TYPEAUDIO)
  321.       ct->subtype = safe_strdup ("basic");
  322.     else if (ct->type == TYPEMESSAGE)
  323.       ct->subtype = safe_strdup ("rfc822");
  324.     else if (ct->type == TYPEOTHER)
  325.     {
  326.       ct->type = TYPEAPPLICATION;
  327.       snprintf (buffer, sizeof (buffer), "x-%s", s);
  328.       ct->subtype = safe_strdup (buffer);
  329.     }
  330.     else
  331.       ct->subtype = safe_strdup ("x-unknown");
  332.   }
  333. }
  334.  
  335. static void parse_content_disposition (char *s, BODY *ct)
  336. {
  337.   PARAMETER *parms;
  338.  
  339.   if (!strncasecmp ("inline", s, 6))
  340.     ct->disposition = DISPINLINE;
  341.   else if (!strncasecmp ("form-dat